package InstanceZone

import (
	codecs "sanguo/codec/cs"
	"sanguo/node/common/DropPool"
	com_attr "sanguo/node/common/attr"
	"sanguo/node/common/com_type"
	"sanguo/node/common/transaction"
	"sanguo/node/node_game"
	"sanguo/node/node_game/module/role"
	"sanguo/node/node_game/user"
	table_BattleLevel "sanguo/node/table/excel/table/BattleLevel"
	table_BossZone "sanguo/node/table/excel/table/BossZone"
	table_GamePlay "sanguo/node/table/excel/table/GamePlay"
	cs_message "sanguo/protocol/cs/message"
	"time"

	"github.com/golang/protobuf/proto"
)

type transactionEnterBossZone struct {
	transaction.TransactionBase
	user    *user.User
	req     *codecs.Message
	resp    *cs_message.EnterBossZoneToC
	errcode cs_message.EnumType
}

func (this *transactionEnterBossZone) GetModuleName() string {
	return "InstanceZone"
}

func (this *transactionEnterBossZone) GetReplyMsg() proto.Message {
	return &cs_message.EnterBossZoneToC{}
}

func (this *transactionEnterBossZone) SetExpiredTime(expired time.Time) {
	this.Expired = expired
}

func (this *transactionEnterBossZone) GetExpiredTime() time.Time {
	return this.Expired
}

func (this *transactionEnterBossZone) Begin() {
	this.resp = &cs_message.EnterBossZoneToC{}
	msg := this.req.GetData().(*cs_message.EnterBossZoneToS)
	roleModule := this.user.GetModuleByName("role").(*role.RoleModule)
	role := roleModule.CurrentRole()
	if role == nil || !role.IsRoleModleData() {
		node_game.Infoln(this.user.GetUserID(), "EnterBossZone fail : no selectRole ")
		this.errcode = cs_message.EnumType_ERROR
		this.user.EndTrans(this)
		return
	}
	node_game.Infof("%s %d Call EnterBossZone id:%d mopTimes:%d", role.GetUserID(), role.GetID(), msg.GetBossZoneID(), msg.GetMopTimes())

	//验证功能开启
	if role.GetLev() < table_GamePlay.Table_.IDMap[com_type.GamePaly_Boss].UnlockLevel {
		node_game.Infoln(role.GetUserID(), role.GetID(), "fail BossZone System is not Unlock")
		this.errcode = cs_message.EnumType_ERROR
		this.user.EndTrans(this)
		return
	}

	if role.GetWeapon1() == 0 {
		node_game.Infoln(role.GetUserID(), role.GetID(), "EnterInstanceZone fail:no weapon")
		this.errcode = cs_message.EnumType_ERROR
		this.user.EndTrans(this)
		return
	}

	bossZone := role.GetRoleBossZone().GetBossZone(msg.GetBossZoneID())
	if bossZone == nil {
		node_game.Infoln(role.GetUserID(), role.GetID(), "EnterBoosZone fail : BossZone is nil ")
		this.errcode = cs_message.EnumType_ERROR
		this.user.EndTrans(this)
		return
	}

	BossZoneDef := table_BossZone.Table_.IDMap[msg.GetBossZoneID()]
	if BossZoneDef == nil {
		node_game.Infoln(role.GetUserID(), role.GetID(), "EnterBoosZone fail : BossZoneDef is nil")
		this.errcode = cs_message.EnumType_ERROR
		this.user.EndTrans(this)
		return
	}

	battleLevel := table_BattleLevel.Table_.IDMap[BossZoneDef.BattleLevel]
	if battleLevel == nil || battleLevel.Type != com_type.InstanceZone_Boss {
		node_game.Infoln(role.GetUserID(), role.GetID(), "EnterBoosZone fail : battleLevel is nil or type is fail")
		this.errcode = cs_message.EnumType_ERROR
		this.user.EndTrans(this)
		return
	}

	ap, _ := role.GetRoleAttr().GetAttr(com_attr.ActionPoint)
	if msg.GetMopTimes() == 0 {
		ap -= int64(BossZoneDef.ActionPointCost)
		if ap < 0 {
			node_game.Infoln(role.GetUserID(), role.GetID(), "EnterBoosZone fail : ap is not enough")
			this.errcode = cs_message.EnumType_ERROR
			this.user.EndTrans(this)
			return
		}

		role.GetRoleBossZone().InitCurrentEnter(msg.GetBossZoneID())
		role.GetRoleAttr().SetAttr(com_attr.ActionPoint, ap)

	} else {
		ap -= int64(BossZoneDef.ActionPointCost * msg.GetMopTimes())
		if ap < 0 {
			node_game.Infoln(role.GetUserID(), role.GetID(), "EnterBoosZone fail : ap is not enough")
			this.errcode = cs_message.EnumType_ERROR
			this.user.EndTrans(this)
			return
		}

		if BossZoneDef.MopCostID != 0 && BossZoneDef.MopCostCount != 0 {
			item := role.GetRoleItem().GetItem(BossZoneDef.MopCostID)
			if item == nil || item.ItemCount < BossZoneDef.MopCostCount*msg.GetMopTimes() {
				node_game.Infoln(role.GetUserID(), role.GetID(), "EnterBoosZone fail : CostItem is not enough")
				this.errcode = cs_message.EnumType_ERROR
				this.user.EndTrans(this)
				return
			}
		}

		awards := []*DropPool.Award{}
		for i := int32(0); i < msg.GetMopTimes(); i++ {
			award := DropPool.InitAward(battleLevel.DropPool)
			if award != nil {
				awards = append(awards, award)
				this.resp.Awards = append(this.resp.Awards, DropPool.PackAward(award))
			}
		}

		role.GetRoleAttr().SetAttr(com_attr.ActionPoint, ap)
		role.GetRoleItem().UseItem(BossZoneDef.MopCostID, BossZoneDef.MopCostCount*msg.GetMopTimes())
		role.OnItemDirty()
		role.GiveOutAward(DropPool.PackAwardsToOne(awards))
	}

	node_game.Infoln(role.GetUserID(), role.GetID(), "EnterBoosZone OK")
	this.errcode = cs_message.EnumType_OK
	this.user.EndTrans(this)
}

func (this *transactionEnterBossZone) End() {
	this.resp.Errcode = cs_message.EnumType(this.errcode).Enum()
	this.user.Reply(this.req.GetSeriNo(), this.resp)
}

func (this *transactionEnterBossZone) Timeout() {
	this.errcode = cs_message.EnumType_RETRY
	this.user.EndTrans(this)
}

func init() {
	user.RegisterTransFunc(&cs_message.EnterBossZoneToS{}, func(user *user.User, msg *codecs.Message) transaction.Transaction {
		return &transactionEnterBossZone{
			user: user,
			req:  msg,
		}
	})
}
